package pacote;

import java.util.Random;

public class Host extends Thread {
	protected Ip ip_host; 
	protected Ip ip_roteador_borda;
	protected Mac end_mac;
	protected Subrede subrede;
	protected int porta;
	protected CamadaDeEnlace enlace;
	
	public Ip getIp() {
		return ip_host;
	}

	public Host(Subrede subrede) {
		this.subrede = subrede;
	}
	
	public boolean N_Activate_Request(){
		if(!inicializaNiveisDeRede(false)) return false;
		if(!inicializaNiveisDeEnlace()) return false;
		if(!inicializaNiveisFisicos()) return false;
		
		return true;
	}
	
	//Solicita transmiss�o de um datagrama
	public void N_Data_Request(Protocolo protocolo, Host host, Ip ip_destino, String dados, int numero_bytes){
		Datagrama datagrama = new Datagrama(ip_host, ip_destino, numero_bytes ,dados);
		enviaDatagrama(datagrama);
	}

	public void enviaDatagrama(Datagrama datagrama) {
		printa("Host Ip: " + ip_host.getIp() + ", Enviando Datagrama, Ip Destino:" + datagrama.getIp_destino().getIp());
		enlace.sendDatagrama(datagrama, end_mac, descobreMac(ip_roteador_borda));
	}

	//Testa se h� um datagrama recebido no n�vel de rede
	public synchronized boolean N_Data_Indication(Protocolo protocolo){
		return enlace.temDatagrama();
	}
	
	//Busca no n�vel de rede os dados do �ltimo datagrama recebido
	public int N_Data_Receive(Protocolo protocolo, Ip ip_sender, int dados_do_datagrama_recebido, int datagrama_data_max_size){
		Datagrama datagrama;
		if((datagrama = enlace.getDatagrama()) != null)
			return datagrama.getTamanho_dos_dados();
		return -1;
	}
	
	//Finaliza o funcionamento do n�veis de rede
	@SuppressWarnings("deprecation")
	public void N_Deactivate_Request(){
		if(ip_host == ip_roteador_borda)
			printa("Roteador de borda Ip:" + ip_host.getIp() + ", Finalizando");
		else
			printa("Host Ip:" + ip_host.getIp() + ", Finalizando");
			
		subrede.recebeIpDevolvido(ip_host);
		ip_host = null;
		ip_roteador_borda = null;
		enlace.stop();
	}
	
	protected boolean inicializaNiveisDeRede(boolean isRoteadorDeBorda){
		ip_host = subrede.getIp(isRoteadorDeBorda);
		ip_roteador_borda = subrede.getIpRoteadorDeBorda();
		
		if( (ip_host == null && ip_roteador_borda == null) ) return false;
		return true;
	}

	protected boolean inicializaNiveisDeEnlace(){
		geraMac();
		subrede.preencheTabelaIp_mac(ip_host, end_mac);
		
		if ( end_mac == null ) return false;
		enlace = new CamadaDeEnlace(end_mac);
		enlace.start();
		return true;
	}

	protected boolean inicializaNiveisFisicos(){
		atualizaPorta();
		return true;
	}
	
	private void atualizaPorta() {
		this.porta = end_mac.getPorta();
	}

	private void geraMac() {
		Random tmp = new Random();
		String string_mac = Integer.toHexString(tmp.nextInt(256)) + "-" + Integer.toHexString(tmp.nextInt(256)) + "-" + Integer.toHexString(tmp.nextInt(256)) + "-" + Integer.toHexString(tmp.nextInt(256)) + "-" + Integer.toHexString(tmp.nextInt(256)) + "-" + Integer.toHexString(tmp.nextInt(256));
		if(end_mac == null)
			end_mac = new Mac(string_mac);
	}
	
	protected Mac descobreMac(Ip ip_destino) {
		return subrede.retornaMac(ip_destino);
	}
	
	public void run() {
		while(true) {
			if (N_Data_Indication(null)){
				Datagrama datagrama = enlace.getDatagrama();
				printa("Host Ip: " + ip_host.getIp() + ", Recebeu de: " + datagrama.getIp_origem().getIp()  + ", Dados -> " + datagrama.getDados());
			}
			try {
				sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	protected synchronized void printa(String string){
		System.out.println(string);
	}
}
